package org.example.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.advice.CustomException;
import org.example.mapper.UserMapper;
import org.example.pojo.User;
import org.example.service.UserService;
import org.example.utils.JwtHelper;
import org.example.utils.MD5Util;
import org.example.utils.Result;
import org.example.utils.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author 宋孟林
 * @description
 */
@Transactional
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtHelper jwtHelper;

    /**
     * 1. 根据账号查询用户对象，我们已经设计了用户的用户名的完整性约束为唯一，
     * 2. 如果没有查询到这个用户对象，说明用户名错误 返回 501 错误
     * 3. 如果查询到了这个用户对象，再将参数的密码和查询出的用户对象的密码进行比对，如果正确则登录，如果失败则返回用户密码错误503 的信息
     * 4. 根据用户id生成一个token， 将token存在result中
     * @param user 用户输入参数
     * @return 结果
     */
    @Override
    public Result<Object> login(User user) {
        if (user == null || StringUtils.isEmpty(user.getUserPwd()) || StringUtils.isEmpty(user.getUsername())) {
//            return Result.build(null, 500, "用户名和密码不能为空");
            throw new CustomException("用户名和密码不能为空");
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername());
        User one = userMapper.selectOne(wrapper);
        if (one == null) {
            return Result.build(null, ResultCodeEnum.USERNAME_ERROR);
        }else {
            String realPwd = one.getUserPwd();
            String inputPwd = user.getUserPwd();
            String encryptPwd = MD5Util.encrypt(inputPwd);
            if (Objects.equals(realPwd, encryptPwd)){
                Long value = one.getUid().longValue();
                String token = jwtHelper.createToken(value);
                Map<String, Object> map = new HashMap<>();
                map.put("token", token);
                return Result.ok(map);
            }else {
                return Result.build(null, ResultCodeEnum.PASSWORD_ERROR);
            }
        }
    }

    /**
     * 1. 先校验token是否过期
     * 2. 根据token来获取用户id
     * 3. 获取后，先将密码置为空字符串，再将获取的user对象封装到result中
     * @param token 1
     * @return 1
     */
    @Override
    public User getUserInfo(String token) {
        //jwt.isExpiration(token) 判断token是否过期 true表示过期
        if (jwtHelper.isExpiration(token)) {
            throw new CustomException("用户未登录");
        }
        int userId = jwtHelper.getUserId(token).intValue();
        User user = userMapper.selectById(userId);
        if (user != null){
            user.setUserPwd("");
            return user;
        }else {
            throw new CustomException("操作异常");
        }
    }

    /**
     * 1. 根据用户名查询用户对象
     * 2. 如果查询到用户对象，则返回true，否则返回false
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public boolean checkUserName(String userName) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, userName);
        return userMapper.selectCount(wrapper) > 0;
    }

    /**
     * 用户注册
     * 1. 检查用户注册的用户名是否可用（是否在数据库中已经存在）
     * 2. 检查用户名是否为空，如果为空返回异常用户名不能为空
     * 3. 将用户密码加密，然后保存用户对象
     * 4. 返回是否成功
     * @param user 用户对象
     * @return 结果
     */
    @Override
    public Result<Object> register(User user) {
        if (user.getUsername() == null || StringUtils.equals(user.getUsername(), "")){
            return Result.build(null, ResultCodeEnum.USERNAME_ERROR);
        }
        //为什么这里还需要检查用户名是否可用？ 因为前面用户名检查那个方法执行的一瞬间有可能被别的用户注册，所以注册时也要检查
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername());
        User one = userMapper.selectOne(wrapper);
        if (one != null){
            return Result.build(null, ResultCodeEnum.USERNAME_USED);
        }
        String encrypt = MD5Util.encrypt(user.getUserPwd());
        user.setUserPwd(encrypt);
        if (this.save(user)) {
            return Result.build(null, ResultCodeEnum.SUCCESS);
        }
        return Result.build(null, 500, "注册失败");
    }
}
